#ifndef BT_HASH_MAP_H
#define BT_HASH_MAP_H

#include "btAlignedObjectArray.h"

const int BT_HASH_NULL = 0xffffffff;

template<class Value>
class btHashKey
{
	int m_uid;
public:

	btHashKey(int uid)
		: m_uid(id)
	{
	}

	int getUid() const
	{
		return m_uid;
	}

	//to our success
	SIMD_FORCE_INLINE unsigned int getHash() const
	{
		int key = m_uid;
		// Thomas Wang's hash
		key += ~(key << 15);
		key ^=  (key >> 10);
		key +=  (key << 3);
		key ^=  (key >> 6);
		key += ~(key << 11);
		key ^=  (key >> 16);
		return key;
	}

	btHashKey getKey(const Value& value) const
	{
		return btHashKey(value.getUid());
	}
};

template<class Value>
class btHashKeyPtr
{
	int m_uid;
public:

	btHashKeyPtr(int uid)
		: m_uid(uid)
	{
	}

	int	getUid() const
	{
		return m_uid;
	}

	//to our success
	SIMD_FORCE_INLINE	unsigned int getHash()const
	{
		int key = m_uid;
		// Thomas Wang's hash
		key += ~(key << 15);
		key ^=  (key >> 10);
		key +=  (key << 3);
		key ^=  (key >> 6);
		key += ~(key << 11);
		key ^=  (key >> 16);
		return key;
	}

	btHashKeyPtr	getKey(const Value& value) const
	{
		return btHashKeyPtr(value->getUid());
	}
};

///The btHashMap template class implements a generic and lightweight hashmap.
///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp
template<class Key, class Value>
class btHashMap
{
	btAlignedObjectArray<int> m_hashTable;
	btAlignedObjectArray<int> m_next;
	btAlignedObjectArray<Value> m_valueArray;

	void growTables(const Key& key)
	{
		int newCapacity = m_valueArray.capacity();

		if (m_hashTable.size() < newCapacity)
		{
			// grow hashtable and next table
			int curHashtableSize = m_hashTable.size();

			m_hashTable.resize(newCapacity);
			m_next.resize(newCapacity);

			int i;

			for (i = 0; i < newCapacity; ++i)
			{
				m_hashTable[i] = BT_HASH_NULL;
			}
			for (i = 0; i < newCapacity; ++i)
			{
				m_next[i] = BT_HASH_NULL;
			}

			for (i = 0; i < curHashtableSize; i++)
			{
				const Value& value = m_valueArray[i];

				int hashValue = key.getKey(value).getHash() & (m_valueArray.capacity() - 1); // New hash value with new mask
				m_next[i] = m_hashTable[hashValue];
				m_hashTable[hashValue] = i;
			}
		}
	}
};

#endif // BT_HASH_MAP_H
